/**
 * This class contains unit tests for validating the behavior of Apex classes
 * and triggers.
 *
 * Unit tests are class methods that verify whether a particular piece
 * of code is working properly. Unit test methods take no arguments,
 * commit no data to the database, and are flagged with the testMethod
 * keyword in the method definition.
 *
 * All test methods in an organization are executed whenever Apex code is deployed
 * to a production organization to confirm correctness, ensure code
 * coverage, and prevent regressions. All Apex classes are
 * required to have at least 75% code coverage in order to be deployed
 * to a production organization. In addition, all triggers must have some code coverage.
 * 
 * The @isTest class annotation indicates this class only contains test
 * methods. Classes defined with the @isTest annotation do not count against
 * the organization size limit for all Apex scripts.
 *
 * See the Apex Language Reference for more information about Testing and Code Coverage.
 */
@isTest
private class WonAndDoneForAccountTest {
	
	private static Integer MAX_QUANTITY_PER_ACCOUNT=10;
	private static String PRICE_BOOK_NAME='Standard Price Book'; 
	    
	private static WonAndDoneForAccountController populateControllerWithIntialData(){
	List< AggregateResult> aggResult= [Select sum(o.Quantity) total_quantity,o.Opportunity.accountid accountid From OpportunityLineItem o WHERE o.CreatedDate = THIS_MONTH group by o.Opportunity.accountid having sum(o.Quantity)<10];	
     Account account =null;
    if(null!= aggResult && !aggResult.isEmpty()){
    	account=[select id,name from Account where id=:  String.valueOf(aggResult.get(0).get('accountid'))];
    }else{
    	account=[select id,name from Account LIMIT 1];
    }
 
    
    ApexPages.currentPage().getParameters().put('accId',String.valueof(account.id));
	WonAndDoneForAccountController wc= new WonAndDoneForAccountController();
	wc.account= account;
	
	Won_and_done_process_settings__c productQuantitySetting =Won_and_done_process_settings__c.getValues('Maximum_product_quantity');
	Won_and_done_process_settings__c priceBookSettings =Won_and_done_process_settings__c.getValues('Price_book_name');
	if(null != productQuantitySetting ){
   		MAX_QUANTITY_PER_ACCOUNT= (null!=productQuantitySetting.get('Value__c')?Integer.valueOf(productQuantitySetting.get('Value__c')):MAX_QUANTITY_PER_ACCOUNT);
   	}
   	if(null != priceBookSettings ){
   		PRICE_BOOK_NAME= (null!=priceBookSettings.get('Value__c')?String.valueOf(priceBookSettings.get('Value__c')):PRICE_BOOK_NAME);
 	}
	return wc;
	}
 
	 /**
 <P> This method test adding single product on the screen. </P>
 */
   static testMethod void testSingleAddProduct() {
  
	WonAndDoneForAccountController wc= populateControllerWithIntialData();
	//Since constructor add one product by default
	System.assert(wc.productDetailsList.size()==1);
	wc.addProduct();

	System.assert(wc.productDetailsList.size()==2);

	}
	
	
/**
 <P> This method test adding 3 products on the screen. </P>
 */
   static testMethod void testMultipleAddProduct() {
	WonAndDoneForAccountController wc= populateControllerWithIntialData();

	//Since constructor add one product by default
	System.assert(wc.productDetailsList.size()==1);
	wc.addProduct();
	wc.addProduct();
	wc.addProduct();
	System.assert(wc.productDetailsList.size()==4);

	}
	
/**
 <P> This method test removing single product from the screen. </P>
 */
   static testMethod void testSingleRemoveProduct() {
   WonAndDoneForAccountController wc= populateControllerWithIntialData();

	//Since constructor add one product by default
	System.assert(wc.productDetailsList.size()==1);
	wc.selectedRowIndex=wc.productDetailsList.get(0).index;
	wc.removeProductSelection();
	System.assert(wc.productDetailsList.size()==0);

	}
	
	
	/**
 <P> This method test removing Multiple (2) products from the screen. </P>
 */
   static testMethod void testMultipleRemoveProduct() {
   WonAndDoneForAccountController wc= populateControllerWithIntialData();

	//Since constructor add one product by default
	System.assert(wc.productDetailsList.size()==1);
	wc.addProduct();
	System.assert(wc.productDetailsList.size()==2);
	wc.selectedRowIndex=wc.productDetailsList.get(0).index;
	wc.removeProductSelection();
	System.assert(wc.productDetailsList.size()==1);
	wc.selectedRowIndex=wc.productDetailsList.get(0).index;
	wc.removeProductSelection();
	
	System.assert(wc.productDetailsList.size()==0);

	}
	
	/**
	 <P> This method test removing item when there is no item to remove product from the screen. </P>
	 */
   static testMethod void testNoItemToRemoveProduct() {
   WonAndDoneForAccountController wc= populateControllerWithIntialData();

	//Since constructor add one product by default
	System.assert(wc.productDetailsList.size()==1);
	wc.selectedRowIndex=1;
	wc.removeProductSelection();
	System.assert(null!=Apexpages.getMessages());

	}
	
	/**
	 <P> This method test removing item from an not existing index to throw an ListException while removing product from the screen. </P>
	 */
   static testMethod void testExceptionOnRemoveProduct() {
   WonAndDoneForAccountController wc= populateControllerWithIntialData();

	//Since constructor add one product by default
	System.assert(wc.productDetailsList.size()==1);
	
	wc.removeProductSelection();
	System.assert(null!=Apexpages.getMessages());

	}
	/**
	<P> this method is used to test the cancel button funtionality. </P>
	*/
	static testMethod void testCancelWonAndDone(){
	
	WonAndDoneForAccountController wc= populateControllerWithIntialData();
	
	wc.cancelWonAndDone();
	
		
	}
	/**
	<P> This method is used to test the Save button funtionality while saving only Opportunity and no
	 Opportunity product. </P>
	*/
	static testMethod void testSaveOnlyOpportunity(){
	
	WonAndDoneForAccountController wc= populateControllerWithIntialData();
	
	wc.opportunity.name='Test opps';
	wc.opportunity.Description='Test opps';
	wc.selectedRowIndex=wc.productDetailsList.get(0).index;
	wc.removeProductSelection();
	wc.save();
	Opportunity opportunity = [Select id from Opportunity where name='Test opps' LIMIT 1];
	
	System.assert(null!=opportunity);
	
		
	}
	
	/**
	<P> This method is used to test the Save button funtionality while saving only Opportunity and one
	 Opportunity product. </P>
	*/
	static testMethod void testSaveOneOLIWithOpportunity(){

	WonAndDoneForAccountController wc= populateControllerWithIntialData();
	wc.opportunity.name='Test oppsAbhishek';
	wc.opportunity.Description='Test oppsAbhishek';
	wc.productDetailsList.get(0).oli.quantity=1;
	wc.productDetailsList.get(0).oli.Unitprice=1;
	wc.productDetailsList.get(0).oli.Term_months__c=1;
	wc.productDetailsList.get(0).oli.PricebookEntryId=wc.products.get(0).getValue();
	
	
	wc.save();
	Opportunity opportunity = [Select id from Opportunity where name='Test oppsAbhishek' LIMIT 1];
	System.assert(null!=opportunity);
	List<OpportunityLineItem> oli=[select id from OpportunityLineItem where opportunityid =:opportunity.id];
	System.assert(1==oli.size());
	
	}
	
	
	/**
	<P> This method is used to test when Save button funtionality while saving only Opportunity and one
	 Opportunity product having quantity more than specified quanity. </P>
	*/
	static testMethod void testSaveOneOLIWithMoreThanMaximumQuantity(){

	WonAndDoneForAccountController wc= populateControllerWithIntialData();
	wc.opportunity.name='Test oppsAbhishek';
	wc.opportunity.Description='Test oppsAbhishek';
	wc.productDetailsList.get(0).oli.quantity=MAX_QUANTITY_PER_ACCOUNT;
	wc.productDetailsList.get(0).oli.Unitprice=1;
	wc.productDetailsList.get(0).oli.Term_months__c=1;
	wc.productDetailsList.get(0).oli.PricebookEntryId=wc.products.get(0).getValue();
	
	
	wc.save();
	System.assert(null!=Apexpages.getMessages());
	
	
	}
	
	/**
	<P> This method is used to test when Won and done process is initiated and Constructor is called, but since Account is already 
	having more than specified quanity of Opportunity product an error is thrown. </P>
	*/
	static testMethod void testMoreThanMaximumQuantityOnPageLoad(){

	List< AggregateResult> aggResult= [Select sum(o.Quantity) total_quantity,o.Opportunity.accountid accountid From OpportunityLineItem o WHERE o.CreatedDate = THIS_MONTH group by o.Opportunity.accountid having sum(o.Quantity)<10];
	Account account =null;
	Integer total_quantity=0;
	if(null!= aggResult && !aggResult.isEmpty()){
    	account=[select id,name from Account where id=:  String.valueOf(aggResult.get(0).get('accountid'))];
    	total_quantity=(null==aggResult.get(0).get('total_quantity')?0:Integer.valueOf(aggResult.get(0).get( 'total_quantity')));
    }else{
    	account=[select id,name from Account LIMIT 1];
    }
    Opportunity opportunity = new Opportunity(AccountId=account.Id , stageName='Closed Won', Closedate=Datetime.now().date(), name='Test oppsAbhishek',Description='Test oppsAbhishek');
    insert opportunity;
    
    PricebookEntry pbk= [select id from PricebookEntry where Pricebook2.Name=:PRICE_BOOK_NAME LIMIT 1];
    OpportunityLineItem oli= new OpportunityLineItem(opportunityid=opportunity.Id,quantity=MAX_QUANTITY_PER_ACCOUNT,unitPrice=10,Term_months__c=1,PricebookEntryId=pbk.Id);
	insert oli;
	
	ApexPages.currentPage().getParameters().put('accId',String.valueof(account.id));
	WonAndDoneForAccountController wc= new WonAndDoneForAccountController();
	System.assert(null!=Apexpages.getMessages());
	}
	
	/**
	<P> This method is used to test when Won and done process is initiated and Constructor is called, but since Account id not provided in paramter 
	 an error is thrown. </P>
	*/
	static testMethod void testNoAccountIdInURLOnPageLoad(){
		WonAndDoneForAccountController wc= new WonAndDoneForAccountController();
		System.assert(null!=Apexpages.getMessages());
	}
	
}